﻿#include <bitset>
#include <unordered_map>
#include <QHash>
#include "FavoriteAttributes.h"
#include "AttributeGroup.h"

AttributeGroup::AttributeGroup(QObject* parent /*= nullptr*/) {
	AttributeGroup(nullptr, parent);
}

AttributeGroup::AttributeGroup(FavoriteAttributes* favorite, QObject* parent /*= nullptr*/)
	: QObject(parent)
	, m_favorite(favorite)
	, m_parseOfBits({
		u"1",
		u"66",
		u"77",
		u"88",
		u"90", u"91", u"92", u"93",
		//u"100", u"101", u"102", u"103", u"104", u"105", u"106", u"107"
	}) {
	for (int i = 0; i < 350; i++) {
		m_lastDataMap[QString::number(i)] = 0;
	}
	m_lastDataMap["100"] = 0xff;
	m_lastDataMap["101"] = 0xff;
	m_lastDataMap["102"] = 0xff;
	m_lastDataMap["103"] = 0xff;
	m_lastDataMap["104"] = 0xff;
	m_lastDataMap["105"] = 0xff;
	m_lastDataMap["106"] = 0xff;
	m_lastDataMap["107"] = 0xff;
	m_lastDataMap["108"] = 0xff;
}

void AttributeGroup::updateLast(QJsonObject const& valueObj) {
	QString key;
	int address = 0;
	quint16 value = 0;
	//qDebug() << valueObj;
	for (auto it = valueObj.constBegin(); it != valueObj.constEnd(); it++) {
		key = it.key();
		address = key.toInt();
		value = quint16(it.value().toInt());
		if (m_favorite && m_favorite->hasFavorite(address)) {
			int bytes = -1;
			bool isOnlyFavorite = false;
			if (m_favorite->hasMulti(address, bytes)) {
				QList<quint16> values;
				for (int i = 0; i < bytes / sizeof(quint16); i++) {
					values << quint16(valueObj[QString::number(address + i)].toInt());
				}
				isOnlyFavorite = m_favorite->update(address, values);
			}	
			else {
				isOnlyFavorite = m_favorite->update(address, value);
			}
			if (isOnlyFavorite) {
				continue;
			}
		}
		updateRegister(key, value);
	}
}

QJsonObject const AttributeGroup::values() const {
	return QJsonObject::fromVariantHash(m_lastDataMap);
}

void AttributeGroup::updateRegister(QString const& key, quint16 value) {
	auto it = m_lastDataMap.find(key);
	auto address = key.toInt();
	if (it != std::end(m_lastDataMap)) {
		if (it.value() != value) {
			if (!updateBits(key, value)) {
				it.value() = value;
				emit registerUpdated(it.key().toInt());
			}
		}
	}
	else {
		m_lastDataMap[key] = value;
		if (std::cend(m_parseOfBits) != std::find(std::cbegin(m_parseOfBits), std::cend(m_parseOfBits), key)) {
			std::bitset<sizeof(quint16) * 8> bits(value);
			for (int i = 0; i < sizeof(quint16) * 8; i++) {
				emit registerUpdated(address, value, bits.test(i));
			}
		}
		else {
			emit registerUpdated(address);
		}
	}
}

bool AttributeGroup::updateBits(QStringView address, quint16 value) {
	auto it = std::find(std::cbegin(m_parseOfBits), std::cend(m_parseOfBits), address);
	if (it == std::cend(m_parseOfBits)) {
		return false;
	}
	std::bitset<sizeof(quint16) * 8> bits(value);
	std::bitset<sizeof(quint16) * 8> other(m_lastDataMap[it->toString()].toInt());
	m_lastDataMap[address.toString()] = value;
	for (int i = 0; i < sizeof(quint16) * 8; i++) {
		if (bits.test(i) != other.test(i)) {
			emit registerUpdated(it->toInt(), i, bits.test(i));
		}
	}
	return true;
}
